package com.dw.widget.slideshow2.launcher;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;

import com.dw.widget.slideshow2.db.helper.ScanFolderHelper;
import com.dw.widget.slideshow2.db.object.ScanFolderData;
import com.dw.widget.slideshow2.objects.FrameAnimationLayouts;
import com.dw.widget.slideshow2.objects.FrameStyle;
import com.dw.widget.slideshow2.thread.AddClipsThread;
import com.dw.widget.slideshow2.thread.ScanFolderImageThread;
import com.dw.widget.slideshow2.utils.AppConfig;
import com.dw.widget.slideshow2.utils.ApplicationEx;
import com.dw.widget.slideshow2.utils.ClipQueue.ImageClip;
import com.dw.widget.slideshow2.utils.DensityUtils;
import com.dw.widget.slideshow2.utils.ImageFileObserver;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;

import com.dw.widget.slideshow2.utils.db.DataObject;
import com.dw.widget.slideshow2.utils.log.Log;
import com.dw.widget.slideshow2.R;

import android.widget.RemoteViews;

public class SlideWidgetService extends Service {

	private final String TAG = "SlideWidgetService";
	
	private final ApplicationEx _APP = ApplicationEx.INSTANCE();
	
	private int TRIGGER_TIME = 1000;
	private int INNER_SWITCH_INTERVAL = 18 * 1000;
	private int INTER_SWITCH_INTERVAL = 300;
	private int SWITCH_WAIT_TIME = 5 * 1000;    // 不同图片切换间等待时间
	
	private int SERVER_NOTIFICATION_ID = 0x8D3A7;
	
	private int[] appWidgetIds;
	
	private Handler threadHandler;
	private PendingIntent piSwitchClip;
	
	private List<ImageFileObserver> imageObservers = new ArrayList<ImageFileObserver>();

	private AppConfig appConfig = null;
	private FrameAnimationLayouts animationLayouts;
	private FrameStyle frameStyle;
	
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	@Override
	public void onStart(Intent intent, int startId) {
		
		Log.d(this, TAG, "onStart");
		super.onStart(intent, startId);
	}

	@Override
	public void onCreate() {
		
		super.onCreate();
		
		// 设置为前台服务级别，提升优先级，防止系统回收删除当前服务
        Notification notification = new Notification(0, null, System.currentTimeMillis());
        notification.flags |= Notification.FLAG_NO_CLEAR;
       
        // 注意使用  startForeground ，id 为 0 将不会显示 notification
        startForeground(SERVER_NOTIFICATION_ID, notification);
		
		_APP.widgetWidthPx = DensityUtils.getScreenWidth(this);  //DensityUtils.dip2px(this, _APP.WIDGET_WIDHT_DP);
		_APP.widgetHeightPx = DensityUtils.dip2px(this, _APP.WIDGET_HEIGHT_DP);
		Log.d(this, TAG, String.format("widthPx:%1$d,  heightPx:%2$d", _APP.widgetWidthPx, _APP.widgetHeightPx));
		
		threadHandler = new Handler()
		{
			@Override
			public void handleMessage(Message msg)
			{

				Bundle data = msg.getData();
				int what = msg.what;
				
				if(what == _APP.THREAD_MSG_ADDCLIP)  // 添加完图片Clip后的回调
				{
					// 初始界面
					setInitImage();
					
					// 启动定时器
					int interval = INTER_SWITCH_INTERVAL;
					if(_APP.LAST_CLIP_IN != null && _APP.LAST_CLIP_IN.isLastClip())
					{
						interval += SWITCH_WAIT_TIME;
					}
					triggerTimer(interval);
				}
				else if(what == _APP.THREAD_MSG_ADDINIT)
				{
					// 加入初始图片数据
					addClips(_APP.INIT_ADD_NUMBER, threadHandler);
				}
				else if(what == _APP.THREAD_MSG_SCANFOLDER)    // 扫描图片文件夹
				{	
					int scanedTotal = data.getInt(_APP.THREAD_PARA_SCANEDTOTAL);
					String added = data.getString(_APP.THREAD_PARA_INITADDED);
					
					if(scanedTotal > 0 && _APP.NO.equals(added))    // 未添加则加入初始图片数据
					{
						addClips(_APP.INIT_ADD_NUMBER, threadHandler);
					}
				}
			}
		};
		
		appConfig = new AppConfig(this, _APP.CONFIG_FILE_NAME);
	}

	@Override
	public void onDestroy() {
		
		super.onDestroy();
		stopForeground(true);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		int cmd = intent.getIntExtra(_APP.INTENT_MSG_SERVICECOMMAND, 0);
		Log.d(this, TAG, "onStartCommand cmd:" + String.valueOf(cmd));
		
		if(cmd == _APP.SERVICE_CMD_STARTWIDGET)
		{
			Log.d(this, TAG, "start widget command");

			int[] widgetIds = intent.getIntArrayExtra(_APP.INTENT_MSG_APPWIDGETIDS);
			if(widgetIds != null)
			{
				appWidgetIds = widgetIds;
			}
			
			// 一些初始化重置工作
			_APP.IMAGE_CACHE.reset();
			_APP.CLIP_QUEUE.reset();
			
			String mediaStatus = Environment.getExternalStorageState();
			Log.d(this, TAG, String.format("Media Status:%1$s", mediaStatus));

			// 读取动画设置
			animationLayouts = getFrameAnimationLayout();
			
			// 根据设置读取相框样式
			frameStyle = getFrameStyle();
			
			// 打开图片文件夹监听器
			AddImageFileObserverThread addThread = new AddImageFileObserverThread(this, threadHandler);
			addThread.start();
			
			if(Environment.MEDIA_MOUNTED.equals(mediaStatus))    // 已有SD卡
			{
				setWidgetStatus(getString(R.string.launching_widget));
				getImageData();
			}
			else   // 没有SD卡或者SD卡未准备好
			{
				setWidgetStatus(getString(R.string.sd_unmounted));
			}
		}
		else if(cmd == _APP.SERVICE_CMD_STOPWIDGET)
		{
			Log.d(this, TAG, "stop widget command");
			AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
			am.cancel(piSwitchClip);
			
			stopSelf();
		}
		else if(cmd == _APP.SERVICE_CMD_SWITCHCLIP)
		{
			Log.d(this, TAG, "ClipQueue left:"+String.valueOf(_APP.CLIP_QUEUE.getCount()));
			
			// 如果是一张图片的末尾则添加新图片
			if(_APP.CLIP_QUEUE.nextClip().isLastClip())
			{
				addClips(1, null);
			}
			
			// 切换图片
			RemoteViews views = setRemoteViews();
			if(views != null)
			{
				updateWidgets(views);
			}
			
			// 启动定时器
			int interval = _APP.LAST_CLIP_OUT.isLastClip() ? INTER_SWITCH_INTERVAL : INNER_SWITCH_INTERVAL;
			if(_APP.LAST_CLIP_IN.isLastClip())
			{
				interval += SWITCH_WAIT_TIME;
			}
			triggerTimer(interval);
		}
		else if(cmd == _APP.SERVICE_CMD_PAUSEWIDGET)    // 暂停切换
		{
			Log.d(this, TAG, "pause widget command");
			AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
			am.cancel(piSwitchClip);
			
			setWidgetStatus(getString(R.string.sd_unmounted));
		}
		
		return super.onStartCommand(intent, flags, startId);
	}
	
	/**
	 * 读取图片数据
	 */
	private void getImageData()
	{
		// 读取文件夹中的图片
		ScanFolderImageThread scanThread = new ScanFolderImageThread(this, threadHandler);
		scanThread.start();
	}
	
	private void addClips(final int number, final Handler callback)
	{
		AddClipsThread thdAddClips = new AddClipsThread(this, callback, number);
		thdAddClips.start();
	}
	
	private void setInitImage()
	{
		ImageClip clip = _APP.CLIP_QUEUE.deQueue();
		if(clip == null)
		{
			return;
		}
		
		RemoteViews rv = new RemoteViews(getPackageName(), R.layout.widget_start);
		rv.setImageViewBitmap(R.id.widget_image, clip.getImage());
		rv.setTextViewText(R.id.widget_statustext, _APP.STATUS_TEXT);
		
		// 设置样式
		setRemoteViewStyle(rv);
		
		_APP.LAST_CLIP_IN = clip;
		
		updateWidgets(rv);
	}
	
	private void triggerTimer(int time)
	{
		Intent intent  = new Intent(this, WidgetProvider.class);
		intent.putExtra(_APP.BROADCAST_INTENT_CMD, _APP.BROADCAST_INTENT_TIMER);
		piSwitchClip = PendingIntent.getBroadcast(this, _APP.SWITCH_BROADCAST_REQCODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		
		Log.d(this, TAG, "Trigger Timer:" + time/1000 + "s");
		AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
		long triggerAtTime = SystemClock.elapsedRealtime() + time;
		am.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, piSwitchClip);
	}
	
	private RemoteViews setRemoteViews()
	{
		ImageClip clip = _APP.CLIP_QUEUE.deQueue();
		if(clip == null)
		{
			return null;
		}
		
		int viewRes = getSwitchLayout(clip.getOrientation());

		RemoteViews rv = new RemoteViews(getPackageName(), viewRes);
		
		// 设置样式
		setRemoteViewStyle(rv);
		
		if(_APP.LAST_CLIP_IN != null)
		{
			Log.d(this, TAG, String.format("widget_imageout=%1$s", _APP.LAST_CLIP_IN.getImage().toString()));
			rv.setImageViewBitmap(R.id.widget_imageout, _APP.LAST_CLIP_IN.getImage());
		}
		Log.d(this, TAG, String.format("widget_imagein=%1$s", clip.getImage().toString()));
		rv.setImageViewBitmap(R.id.widget_imagein, clip.getImage());

		if(_APP.LAST_CLIP_OUT != null)
		{
			_APP.LAST_CLIP_OUT.getImage().recycle();
		}
		
		_APP.LAST_CLIP_OUT = _APP.LAST_CLIP_IN;
		_APP.LAST_CLIP_IN = clip;
		
		return rv;
	}
	
	private void setRemoteViewStyle(RemoteViews rv)
	{
		rv.setInt(R.id.widget_container, "setBackgroundResource", frameStyle.getBackgroundDrawable());
		rv.setImageViewResource(R.id.widget_mask, frameStyle.getForegroundDrawable());
	}
	
	/**
	 * 获取下一次切换的布局
	 * @return
	 */
	private int getSwitchLayout(String orientation)
	{
		int viewRes = animationLayouts.getAnimationLayout1();
		if(_APP.LAST_CLIP_IN != null)
		{
			if(_APP.LAST_CLIP_IN.isLastClip())   // 下一次切换为不同图片间的切换
			{
				viewRes = _APP.LAST_SWITCH_LAYOUT == animationLayouts.getAnimationLayout1() ? animationLayouts.getAnimationLayout2() : animationLayouts.getAnimationLayout1();
			}
			else      // 下一次切换为图片内不同clip的切换
			{
				if(_APP.VERTICAL.equals(orientation))
				{
					viewRes = _APP.LAST_SWITCH_LAYOUT == R.layout.widget_inter_1 ? R.layout.widget_inter_2 : R.layout.widget_inter_1;
				}
				else
				{
					viewRes = _APP.LAST_SWITCH_LAYOUT == R.layout.widget_inter_3 ? R.layout.widget_inter_4 : R.layout.widget_inter_3;
				}
			}
		}
		
		_APP.LAST_SWITCH_LAYOUT = viewRes;
		
		return viewRes;
	}
	
	/**
	 * 根据动画设置读取layout
	 * @return
	 */
	private FrameAnimationLayouts getFrameAnimationLayout()
	{
		int animation = appConfig.getInt(_APP.CONFIG_ITEM_ANIMATION);
		
		int layout1 = R.layout.widget_ex_slide_1;
		int layout2 = R.layout.widget_ex_slide_2;
		switch(animation)
		{
			case ApplicationEx.ANIMATION_STYLE1:
			{
				layout1 = R.layout.widget_ex_slide_1;
				layout2 = R.layout.widget_ex_slide_2;
				break;
			}
			case ApplicationEx.ANIMATION_STYLE2:
			{
				layout1 = R.layout.widget_ex_fade_1;
				layout2 = R.layout.widget_ex_fade_2;
				break;
			}
			case ApplicationEx.ANIMATION_STYLE3:
			{
				layout1 = R.layout.widget_ex_zoom_1;
				layout2 = R.layout.widget_ex_zoom_2;
				break;
			}
			case ApplicationEx.ANIMATION_STYLE4:
			{
				layout1 = R.layout.widget_ex_rotate90_3;
				layout2 = R.layout.widget_ex_rotate90_4;
				break;
			}
			case ApplicationEx.ANIMATION_STYLE5:
			{
				layout1 = R.layout.widget_ex_rotate90_1;
				layout2 = R.layout.widget_ex_rotate90_2;
				break;
			}
		}
		
		FrameAnimationLayouts layout = new FrameAnimationLayouts();
		layout.setAnimationLayout1(layout1);
		layout.setAnimationLayout2(layout2);
		
		return layout;
	}
	
	/**
	 * 根据设置选项设置相框样式
	 * @return
	 */
	private FrameStyle getFrameStyle()
	{
		// 根据设置选项设置相框样式
		int frameStyle = appConfig.getInt(_APP.CONFIG_ITEM_FRAME);
		
		int bgRes = R.drawable.frame5_1, fgRes = R.drawable.transparent;
		switch(frameStyle)
		{
			case ApplicationEx.FRAME_STYLE1:
			{
				bgRes = R.drawable.frame5_1;
				fgRes = R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE2:
			{
				bgRes = R.drawable.frame2_1;
				fgRes = R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE3:
			{
				bgRes = R.drawable.frame4_1;
				fgRes =  R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE4:
			{
				bgRes = R.drawable.frame3_1;
				fgRes = R.drawable.frame3_2;
				break;
			}
			case ApplicationEx.FRAME_STYLE5:
			{
				bgRes = R.drawable.frame1_1;
				fgRes =  R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE6:
			{
				bgRes = R.drawable.frame7_1;
				fgRes =  R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE7:
			{
				bgRes = R.drawable.frame6_1;
				fgRes =  R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE8:
			{
				bgRes = R.drawable.frame8_1;
				fgRes =  R.drawable.transparent;
				break;
			}
			case ApplicationEx.FRAME_STYLE9:
			{
				bgRes = R.drawable.transparent;
				fgRes =  R.drawable.transparent;
				break;
			}
		}
		
		FrameStyle style = new FrameStyle();
		style.setBackgroundDrawable(bgRes);
		style.setForegroundDrawable(fgRes);
		
		return style;
	}
	
	/*
	 * 更新Widget
	 */
	private void updateWidgets(RemoteViews views)
	{
		if(appWidgetIds == null || appWidgetIds.length <= 0 || views == null)
		{
			return;
		}
		
		AppWidgetManager.getInstance(SlideWidgetService.this).updateAppWidget(appWidgetIds, views);
	}
	
	/**
	 * 设置当前Widget状态信息
	 * @param status
	 */
	private void setWidgetStatus(String status)
	{
		_APP.STATUS_TEXT = status;
		
		RemoteViews rv = new RemoteViews(getPackageName(), R.layout.widget_status);
		rv.setTextViewText(R.id.widget_statustext, status);
		
		updateWidgets(rv);
	}
	
	private void addImageFileObservers(String path)
	{
		ImageFileObserver observer = new ImageFileObserver(this, path);
		observer.startWatching();
		
		imageObservers.add(observer);
	}
	
	private void removeImageFileObservers()
	{
		for(ImageFileObserver observer : imageObservers)
		{
			observer.stopWatching();
		}
	}
	
	private class AddImageFileObserverThread extends Thread{
		
		private Context context;
		private Handler handler;
		
		public AddImageFileObserverThread(Context context, Handler handler)
		{
			this.context = context;
			this.handler = handler;
		}
		
		@Override
		public void run()
		{
			ScanFolderHelper dbHelper = new ScanFolderHelper(context, _APP.DB_NAME, ScanFolderData.class);
			ScanFolderData condition = null;
			List<DataObject> folders = dbHelper.query(condition);
			
			for(DataObject obj : folders)
			{
				ScanFolderData folder = (ScanFolderData)obj;
				String folderPath = folder.getFolder();
				addFileObserver(folderPath);
			}
		}
		
		private void addFileObserver(String path)
		{
			if(path == null || "".equals(path))
			{
				return;
			}
			
			File folder = new File(path);
			if(folder.isDirectory() == false)
			{
				return;
			}
			
			// add current folder to observer
			addImageFileObservers(path);
			Log.d(SlideWidgetService.this, "AddImageFileObserverThread", String.format("add file observer: %1$s", path));
			
			// add sub folders
			File[] subFolders = folder.listFiles(new FileFilter() {
				
				@Override
				public boolean accept(File pathname) {
					
					if(pathname.isDirectory())
					{
						return true;
					}
					
					return false;
				}
			});
			
			if(subFolders != null)
			{
				for(File subFolder : subFolders)
				{
					addFileObserver(subFolder.getAbsolutePath());
				}
			}
		}
	}
}
